package validate

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"gitee.com/bobo-rs/creative-framework/pkg/algorithm/uniquecode"
	"gitee.com/bobo-rs/creative-framework/pkg/utils"
	"gitee.com/bobo-rs/innovideo-services/library/exception"
	"gitee.com/bobo-rs/innovideo-services/library/tools"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/util/gvalid"
	"regexp"
)

// RuleRegisterCommon 注册公共规则
func RuleRegisterCommon() {
	gvalid.RegisterRuleByMap(map[string]gvalid.RuleFunc{
		`alpha-dash`:    RuleAlphaDash,
		`alpha-num`:     RuleAlphaNum,
		`chs-dash`:      RuleChsDash,
		`chs-alpha-num`: RuleChsAlphaNum,
		`is-hex`:        RuleIsHex,
		`sms-captcha`:   RuleSmsCaptcha,
		`dates`:         RuleDates,
		`strings`:       RuleStrings,
		`is_json`:       RuleIsJson,
		`search-at`:     RuleSearchAt,
		`is-no`:         RuleIsNo,
		`is-email`:      RuleIsEmail,
	})
}

// RuleAlphaDash 匹配字母数字下划线和破折号
func RuleAlphaDash(ctx context.Context, in gvalid.RuleFuncInput) error {
	if len(in.Value.String()) == 0 {
		return nil
	}
	if !utils.AlphaDash(in.Value.String()) {
		if len(in.Message) == 0 {
			in.Message = `只允许字母和数字，下划线_及破折号-`
		}
		return gerror.New(in.Message)
	}
	return nil
}

// RuleAlphaNum 字母和数字
func RuleAlphaNum(ctx context.Context, in gvalid.RuleFuncInput) error {
	if len(in.Value.String()) == 0 {
		return nil
	}
	if !utils.AlphaNum(in.Value.String()) {
		if len(in.Message) == 0 {
			in.Message = `只允许字母和数字`
		}
		return gerror.New(in.Message)
	}
	return nil
}

// RuleChsDash  验证汉字、字母和数字，下划线_及破折号-
func RuleChsDash(ctx context.Context, in gvalid.RuleFuncInput) error {
	if len(in.Value.String()) == 0 {
		return nil
	}
	if !utils.ChsDash(in.Value.String()) {
		if len(in.Message) == 0 {
			in.Message = `只允许汉字、字母和数字，下划线_及破折号-`
		}
		return gerror.New(in.Message)
	}
	return nil
}

// RuleChsAlphaNum 匹配汉字、字母和数字
func RuleChsAlphaNum(ctx context.Context, in gvalid.RuleFuncInput) error {
	if len(in.Value.String()) == 0 {
		return nil
	}
	if !utils.ChsAlphaNum(in.Value.String()) {
		if len(in.Message) == 0 {
			in.Message = `只允许汉字、字母和数字`
		}
		return gerror.New(in.Message)
	}
	return nil
}

// RuleIsHex 匹配十六进制
func RuleIsHex(ctx context.Context, in gvalid.RuleFuncInput) error {
	if !utils.IsHex(in.Value.String()) {
		return gerror.New(in.Message)
	}
	return nil
}

// RuleSmsCaptcha 短信验证码
func RuleSmsCaptcha(ctx context.Context, in gvalid.RuleFuncInput) error {
	if !regexp.MustCompile(`^[\d]{6}$`).MatchString(in.Value.String()) {
		return gerror.New(in.Message)
	}
	return nil
}

// RuleDates 验证时间格式组
func RuleDates(ctx context.Context, in gvalid.RuleFuncInput) error {
	if len(in.Value.Strings()) == 0 {
		return nil
	}
	// 解析时间格式
	for _, date := range in.Value.Strings() {
		if !tools.IsValidDateTime(date) {
			return exception.Newf(`[%s]时间格式错误`, date)
		}
	}
	return nil
}

// RuleStrings 验证数组字符串
func RuleStrings(ctx context.Context, in gvalid.RuleFuncInput) error {
	if len(in.Value.Strings()) == 0 {
		return nil
	}

	// 格式验证
	for _, val := range in.Value.Strings() {
		if !utils.ChsDash(val) {
			if len(in.Message) == 0 {
				in.Message = fmt.Sprintf(`[%s]只允许汉字、字母和数字，下划线_及破折号-`, val)
			}
			return gerror.New(in.Message)
		}
	}
	return nil
}

// RuleIsJson 验证JSON格式
func RuleIsJson(ctx context.Context, in gvalid.RuleFuncInput) error {
	if in.Value == nil {
		return nil
	}
	buffer, err := json.Marshal(in.Value)
	if err != nil {
		return exception.New(`非JSON格式`)
	}

	if json.NewDecoder(bytes.NewBuffer(buffer)).More() {
		return exception.New(`JSON格式错误`)
	}
	return nil
}

// RuleSearchAt 验证搜索查询时间
func RuleSearchAt(ctx context.Context, in gvalid.RuleFuncInput) error {
	if len(in.Value.String()) == 0 {
		return nil
	}
	// 时间格式是否存在
	if len(tools.FmtSearchDate(in.Value.String())) == 0 {
		return exception.New(`搜索时间格式错误，支持YYYY-mm-dd HH:ii:ss,YYYY-mm-dd HH:ii:ss逗号分割搜索时间`)
	}
	return nil
}

// RuleIsNo 验证系统编号格式
func RuleIsNo(ctx context.Context, in gvalid.RuleFuncInput) error {
	if in.Value.IsEmpty() {
		return nil
	}
	// 验证规则
	if !uniquecode.CheckUniqueCode(in.Value.String(), true) {
		return exception.New(in.Message)
	}
	return nil
}

// RuleIsEmail 匹配邮件格式
func RuleIsEmail(ctx context.Context, in gvalid.RuleFuncInput) error {
	if len(in.Value.String()) == 0 {
		return nil
	}
	emails := utils.SplitSymbolWords(in.Value.String())
	if len(emails) == 0 {
		return exception.New(`邮件地址格式错误，地址为空`)
	}
	for _, email := range emails {
		if !utils.IsEmail(email) {
			return exception.Newf(`[%s]邮件格式错误`, email)
		}
	}
	return nil
}
